class Signal(object):
    __slots__ = ["_notifying", "_observers"]
    def __init__(self):
        self._notifying = False
        self._observers = []
    def register(self, observer):
        self._observers.append(observer)
    def unregister(self, observer):
        self._observers.remove(observer)
    def notify(self, *args):
        if self._notifying:
            return
        self._notifying = True
        try:
            for observer in self._observers[:]:
                observer(*args)
        finally:
            self._notifying = False
    __call__ = notify

class SObject(object):
    __slots__ = ["_signal"]
    def __init__(self):
        self._signal = Signal()
    def register(self, observer):
        self._signal.register(observer)
    def unregister(self, observer):
        self._signal.unregister(observer)

class SValue(SObject):
    """container for an opaque value, supports set() and get()"""
    __slots__ = ["_value"]
    def __init__(self, initvalue = None):
        SObject.__init__(self)
        self._value = initvalue
    def get(self):
        return self._value
    def set(self, value):
        self._value = value
        self._signal.notify(self)

class SList(list): # can't inherit from both list and SObject...
    __slots__ = ["_signal"]
    def __init__(self, seq = ()):
        list.__init__(self, seq)
        self._signal = Signal()
    def register(self, observer):
        self._signal.register(observer)
    def unregister(self, observer):
        self._signal.unregister(observer)
    
    methods = ("__iadd__", "__imul__", "__delitem__", "__delslice__", 
        "__setitem__", "__setslice__", "append", "extend", "insert", "pop", 
        "remove", "reverse", "sort")
    for name in methods:
        exec """def %(name)s(self, *args):
                    ret = list.%(name)s(self, *args)
                    self._signal.notify(self, %(name)r, *args)
                    return ret""" % {"name" : name}
    del methods, name

class STreeCursor(SValue):
    def __init__(self):
        SValue.__init__(self, None)
        self.tree = None
    def _init(self, tree):
        self.tree = tree
    def get_node(self):
        return self.tree.get_model()._get_node_by_path(self._value)
    def expand(self):
        self.tree.expand_row(self._value, False)
    def collapse(self):
        self.tree.collapse_row(self._value)

    def expand_down(self):
        path = self._value
        if not path:
            return
        if self.tree.expand_row(path, False) or self.tree.row_expanded(path):
            self.set(self._value + (0,))
            self.tree.columns_autosize()
    def collapse_up(self):
        if not self._value or len(self._value) <= 1:
            return
        self.set(self._value[:-1])
        self.tree.collapse_row(self._value)
        self.tree.columns_autosize()






